/**
 *    Copyright (C) 2008, 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_API_COLLECTIONS_CONTAINER_HPP
#define	_CUBEFS_CORE_API_COLLECTIONS_CONTAINER_HPP

#include <cubefs/api/metadata.hpp>
#include <cubefs/api/models/container.hpp>
#include <cubefs/api/tools/plugin.hpp>

#include <cubefs/core/api/models/tree_map.hpp>
#include <cubefs/core/api/models/manager.hpp>

#include <cubefs/core/api/reflection/type.hpp>
#include <cubefs/core/api/reflection/basic_operation.hpp>
#include <cubefs/core/api/reflection/basic_typed_operation.hpp>

namespace cubefs    {
namespace api       {

template <>
struct TypeFactory<ContainerTypeCodes> {
    static Type* type() {
        return TypedValue<ContainerTypeCodes>::MyType();
    }
};

template <typename Interface>
class ContainerImplT: public TypedImplT<Interface> {
	typedef ContainerImplT<Interface> 	Me;
	typedef TypedImplT<Interface>		Base;
public:

	ContainerImplT(): plugin_(NULL) {}

	virtual ~ContainerImplT() throw () {
		try {
			if (plugin_ != NULL)
			{
				try {
					plugin_->GetLibrary().Close();
				}
				catch (...) {}
				delete plugin_;
			}
		}
		catch (...) {}
	}

    virtual Int ContainerType() {
        return containerType_;
    }

    virtual void SetContainerType(Int container_type) {
        containerType_ = container_type;
    }

    virtual TreeMap *GetRootMap()                               = 0;
    virtual Manager* GetManager()                               = 0;

    virtual Model* GetCollection(TypedIDValue* rootId)          = 0;
    virtual Model* GetCollectionByName(BigInt name)             = 0;

    virtual Model* CreateCollection(Int type, BigInt name)      = 0;
    virtual void ReleaseCollection(Model* collection)           = 0;
    virtual void RemoveCollection(Model* collection)            = 0;

    virtual bool Check()                                        = 0;

    virtual bool managed() const {
        return false;
    }

    virtual ContainerMetadata* 	GetMetadata() = 0;

//    static Container*  	Create(StringRef name);
//    static ListOfTyped*	GetAvailableContainerNames();

    virtual void SetPlugin(Plugin* plugin) {
    	plugin_ = plugin;
    }

    virtual Plugin* GetPlugin()	{
    	return plugin_;
    }

    static void InitType() {
    	AbstractType *type = new AbstractType(TypeNameFactory<Interface>::name(), Typed::MyType());
    	type_ = type;
    }

    static void InitOperations() {
    	AbstractType* type = static_cast<AbstractType*>(type_);

    	type->AddOperation(new BasicOperation<Int (Me::*)()>(type, "ContainerType", &Me::ContainerType));
    	type->AddOperation(new BasicStaticOperation<Typed* (*)(StringRef, StringRef, Int), Container* (*)(StringRef, StringRef, Int)>(type, Container::MyType(), "Create", "name", "version", "type", &Me::Create));

    	type->AddOperation(new BasicOperation<Typed* (Me::*)(), ContainerMetadata* (Me::*)()>(type, ContainerMetadata::MyType(), "GetMetadata", &Me::GetMetadata));

    	type->AddOperation(new BasicOperation<Typed* (Me::*)(), Manager* (Me::*)()>(type, Manager::MyType(), "GetManager", &Me::GetManager));

    	type->AddOperation(new BasicOperation<Typed* (Me::*)(), TreeMap* (Me::*)()>(type, TreeMap::MyType(), "roots", &Me::GetRootMap));

    	type->AddOperation(new BasicOperation<Typed* (Me::*)(TypedIDValue*), Model* (Me::*)(TypedIDValue*)>(type, Model::MyType(), "GetCollection", "rootId", &Me::GetCollection));
    	type->AddOperation(new BasicOperation<Typed* (Me::*)(BigInt), Model* (Me::*)(BigInt)>(type, Model::MyType(), "GetCollectionByName", "name", &Me::GetCollectionByName));

    	type->AddOperation(new BasicOperation<bool (Me::*)()>(type, "Check", &Me::Check));

    	type->AddOperation(new BasicOperation<Typed* (Me::*)(Int, BigInt), Model* (Me::*)(Int, BigInt)>(type, Model::MyType(), "CreateCollection", "code", "name", &Me::CreateCollection));
    	type->AddOperation(new BasicOperation<void (Me::*)(Model*)>(type, "RemoveCollection", "model", &Me::RemoveCollection));
    }

    CUBEFS_DECLARE_REFLECTION;

private:
    Int containerType_;
    Plugin* plugin_;
};

template <typename Interface>
Type* ContainerImplT<Interface>::type_ 			= NULL;

typedef ContainerImplT<Container> 				ContainerImpl;



}
}


#endif
